/**
 * 
 */
package junweixu.jreader;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Region;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;

/**
 * @author HiyJeain
 * 
 */
public class BookPage extends View
{

    private static final int LEFT_UP_CORNER = 0;

    private static final int RIGHT_UP_CORNER = 1;

    private static final int LEFT_DOWN_CORNER = 2;

    private static final int RIGHT_DOWN_CORNER = 3;

    private static final int NOT_TURN = -1;
    Scroller mScroller;
    private int dragType = NOT_TURN;

    @Override
    protected void onDraw(Canvas canvas)
    {
        // TODO Auto-generated method stub
        canvas.drawColor(0xFFAAAAAA);

        calPoint();
        calPath();
        drawCurPage(canvas);
        drawNextPage(canvas);
        drawPage(canvas);
    }

    private int mScreenWidth;
    private int mScreenHeight;
    Bitmap mCurPageBitmap = null;
    Bitmap mNextPageBitmap = null;
    Paint mPaint;
    PointF aPoint = new PointF();
    PointF bPoint = new PointF();
    PointF cPoint = new PointF();
    PointF dPoint = new PointF();
    PointF dragPoint = new PointF();

    PointF crossBottomPoint = new PointF();
    PointF crossSidePoint = new PointF();
    PointF cornerPoint = new PointF();
    PointF controlPoint = new PointF();
    PointF dyaPoint = new PointF();

    Path pagePath;
    Path nextPagePath;

    /**
     * @param context
     */
    public BookPage(Context context, int mScreenWidth, int mScrrenHeight)
    {
        super(context);
        mScroller = new Scroller(getContext());
        this.mScreenWidth = mScreenWidth;
        this.mScreenHeight = mScrrenHeight;
        initStaticPoints();
        pagePath = new Path();
        nextPagePath = new Path();

        // TODO Auto-generated constructor stub
    }

    public void setBitmaps(Bitmap mCur, Bitmap mNext)
    {
        this.mCurPageBitmap = mCur;
        this.mNextPageBitmap = mNext;
    }

    private void drawCurPage(Canvas canvas)
    {
        canvas.save();
        canvas.clipPath(pagePath, Region.Op.XOR);
        canvas.drawBitmap(mCurPageBitmap, 0, 0, null);
        canvas.restore();
    }

    private void drawNextPage(Canvas canvas)
    {
        canvas.save();
        canvas.clipPath(nextPagePath);
        canvas.drawBitmap(mNextPageBitmap, 0, 0, null);
        canvas.restore();
    }

    private void drawPage(Canvas canvas)
    {
        canvas.save();
        canvas.clipPath(pagePath);
        canvas.drawColor(0xFFFFFFFF);
        canvas.restore();
    }

    private void initStaticPoints()
    {
        aPoint.set(0, 0);
        bPoint.set(mScreenWidth, 0);
        cPoint.set(0, mScreenHeight);
        dPoint.set(mScreenWidth, mScreenHeight);
    }

    private void calPoint()
    {
        float mY;
        float mX;
        // cal Cross bottom
        mX = ((cornerPoint.y - dragPoint.y) * (cornerPoint.y - dragPoint.y))
                / ((dragPoint.x - cornerPoint.x) + (dragPoint.x - cornerPoint.x))
                + (cornerPoint.x + dragPoint.x) / 2;
        mY = controlPoint.y;
        if (dragPoint.x < 0 || dragPoint.x > mScreenWidth)
        {
            crossBottomPoint.set(mX, mY);
        } else if (mX < 0 || mX > mScreenWidth)
        {
            mX = (float) Math
                    .sqrt((mScreenWidth * mScreenWidth)
                            / (1 + ((dragPoint.y - controlPoint.y) * (dragPoint.y - controlPoint.y))
                                    / ((dragPoint.x - controlPoint.x) * (dragPoint.x - controlPoint.x))));
            if (controlPoint.x > 0)
            {
                mX = controlPoint.x - mX;
            } else
            {
                mX += controlPoint.x;
            }

            mY = (float) Math
                    .sqrt((mScreenWidth * mScreenWidth)
                            / (1 + ((dragPoint.x - controlPoint.x) * (dragPoint.x - controlPoint.x))
                                    / ((dragPoint.y - controlPoint.y) * (dragPoint.y - controlPoint.y))));
            if (controlPoint.y > 0)
            {
                mY = controlPoint.y - mY;
            } else
            {
                mY += controlPoint.y;
            }

            dragPoint.set(mX, mY);
            crossBottomPoint.set(controlPoint);
        } else
        {
            crossBottomPoint.set(mX, mY);
        }
        // cal Cross side
        mY = ((cornerPoint.x - dragPoint.x) * (cornerPoint.x - dragPoint.x))
                / ((dragPoint.y - cornerPoint.y) + (dragPoint.y - cornerPoint.y))
                + (cornerPoint.y + dragPoint.y) / 2;
        mX = cornerPoint.x;
        if (mY < 0 || mY > mScreenHeight)
        {
            mX = ((cornerPoint.y + dragPoint.y) * (cornerPoint.y - dragPoint.y))
                    / ((cornerPoint.x - dragPoint.x) + (cornerPoint.x - dragPoint.x))
                    + ((cornerPoint.x + dragPoint.x) / 2);
            mY = dyaPoint.y;
        }
        crossSidePoint.set(mX, mY);

    }

    private void calPath()
    {

        nextPagePath.reset();
        pagePath.reset();

        pagePath.moveTo(dragPoint.x, dragPoint.y);
        pagePath.lineTo(crossBottomPoint.x, crossBottomPoint.y);

        pagePath.lineTo(crossSidePoint.x, crossSidePoint.y);
        if (dyaPoint.y == crossSidePoint.y)
        {
            if (dragType == LEFT_DOWN_CORNER || dragType == LEFT_UP_CORNER)
            {
                pagePath.lineTo(
                        Math.abs(dyaPoint.x - 2
                                * Math.abs(dyaPoint.x - crossSidePoint.x)),
                        crossSidePoint.y);
            } else if (dragType == RIGHT_DOWN_CORNER
                    || dragType == RIGHT_UP_CORNER)
            {
                pagePath.lineTo(
                        dyaPoint.x - 2
                                * Math.abs(dyaPoint.x - crossSidePoint.x),
                        crossSidePoint.y);
            }

        }
        pagePath.lineTo(dragPoint.x, dragPoint.y);
        pagePath.close();

        Log.e("hiyjeain", dragPoint.x + "," + dragPoint.y);
        nextPagePath.moveTo(cornerPoint.x, cornerPoint.y);
        nextPagePath.lineTo(crossBottomPoint.x, crossBottomPoint.y);
        nextPagePath.lineTo(crossSidePoint.x, crossSidePoint.y);
        if (dyaPoint.y == crossSidePoint.y)
        {
            nextPagePath.lineTo(dyaPoint.x, dyaPoint.y);
        }
        nextPagePath.lineTo(cornerPoint.x, cornerPoint.y);
        nextPagePath.close();
    }

    public void calcPoints(float mX, float mY)
    {
        if (mX > mScreenWidth / 2 && mY > mScreenHeight / 2)
        {
            dragType = RIGHT_DOWN_CORNER;
            controlPoint.set(cPoint);
            cornerPoint.set(dPoint);
            dyaPoint.set(bPoint);
        } else if (mX > mScreenWidth / 2 && mY <= mScreenHeight / 2)
        {
            dragType = RIGHT_UP_CORNER;
            controlPoint.set(aPoint);
            cornerPoint.set(bPoint);
            dyaPoint.set(dPoint);
        } else if (mX <= mScreenWidth / 2 && mY > mScreenHeight / 2)
        {
            dragType = LEFT_DOWN_CORNER;
            controlPoint.set(dPoint);
            cornerPoint.set(cPoint);
            dyaPoint.set(aPoint);
        } else
        {
            dragType = LEFT_UP_CORNER;
            controlPoint.set(bPoint);
            cornerPoint.set(aPoint);
            dyaPoint.set(cPoint);
        }

    }

    public boolean doTouchEvent(MotionEvent event)
    {
        dragPoint.x = event.getX();
        dragPoint.y = event.getY();
        offsetDragPoint();
        if (event.getAction() == MotionEvent.ACTION_DOWN)
        {
            calcPoints(event.getX(), event.getY());
        } else if (event.getAction() == MotionEvent.ACTION_MOVE)
        {

            this.postInvalidate();
        } else if (event.getAction() == MotionEvent.ACTION_UP)
        {
            startAnimation(1000);
            this.postInvalidate();
        }

        return true;
    }

    private void offsetDragPoint()
    {
        if (dragPoint.x == 0)
        {
            dragPoint.x += 0.1;
        }
        if (dragPoint.x == mScreenWidth)
        {
            dragPoint.x -= 0.1;
        }
        if (dragPoint.y == 0)

        {
            dragPoint.y += 0.1;
        }
        if (dragPoint.y == mScreenHeight)
        {

            dragPoint.y -= 0.1;
        }
    }

    private void startAnimation(int delayMillis)
    {
        int dx, dy;
        if (cornerPoint.x > 0)
        {
            dx = -(int) (mScreenWidth + dragPoint.x);
        } else
        {
            dx = (int) (mScreenWidth - dragPoint.x + mScreenWidth);
        }
        if (cornerPoint.y > 0)
        {
            dy = (int) (mScreenHeight - dragPoint.y);
        } else
        {
            dy = (int) (1 - dragPoint.y); // 防止dragPoint.y最终变为0
        }
        mScroller.startScroll((int) dragPoint.x, (int) dragPoint.y, dx, dy,
                delayMillis);
    }

    @Override
    public void computeScroll()
    {
        // TODO Auto-generated method stub
        super.computeScroll();
        if (mScroller.computeScrollOffset())
        {
            float x = mScroller.getCurrX();
            float y = mScroller.getCurrY();
            dragPoint.x = x;
            dragPoint.y = y;
            postInvalidate();
        }
    }

    public void abortAnimation()
    {
        if (!mScroller.isFinished())
        {
            mScroller.abortAnimation();
        }
    }
}
